#include <stdio.h>
#include <iostream>
#include <locale.h>
#include <thread>
#include <string>
#include <list>
#include <chrono>
#include <sstream>
#include <fstream>
#include <filesystem>
#include <boost/locale.hpp>
#include <boost/asio.hpp>
#include <boost/asio/thread_pool.hpp>

#include "common/filedirs.hpp"

#define MAXNAME 255+3
extern "C" void ScanDirectory(const wchar_t* directory, long long size, BOOL recursive, void (*)(wchar_t* path,wchar_t* file,int action,void*), void*);
extern "C" void WatchDirectoryChanges(const wchar_t* directory, long long size, void (*)(wchar_t* file,int action,void*),void*);
std::shared_ptr<boost::asio::thread_pool> pool;
std::function<void(std::wstring,std::list<Dir>*)> scan_file,watch_file;
int main()
{
    char *zErrMsg = 0;
    std::setlocale(LC_ALL, "");
    std::wcout.imbue(std::locale(""));
    auto start = std::chrono::high_resolution_clock::now();
    scan_file = [](std::wstring dir,std::list<Dir>* pdir){
        std::filesystem::path paths(dir.c_str());
        dir.resize(dir.size()+3);
        pdir->emplace_back(Dir{paths.wstring().back()==L':'?paths.root_name().wstring():paths.filename().wstring()});
        ScanDirectory(dir.c_str(),dir.size(), false, [](wchar_t* path, wchar_t* file,int action,void* obj){
            Dir* pdir = (Dir*)obj;
            std::filesystem::path dirname(path),filename(file);
            if(action==1){
                boost::asio::post(*pool.get(), std::bind(scan_file,(dirname/filename).wstring(),&pdir->dirs));
            }else{
                //wprintf(L"%s\n",(dirname/filename).wstring().c_str());
                pdir->files.emplace((dirname/filename).filename().wstring());
            }
        },&pdir->back());
    };
    watch_file = [&](std::wstring dir,std::list<Dir>*){
        WatchDirectoryChanges(dir.c_str(),dir.size(), [](wchar_t* file,int action, void* obj){
            switch (action) {
                case 1:
                    //wprintf(L"File added: %s\n", file);
                    break;
                case 2:
                    //wprintf(L"File removed: %s\n", file);
                    break;
                case 3:
                    //wprintf(L"File modified: %s\n", file);
                    break;
                case 4:
                    //wprintf(L"File renamed (old name): %s\n", file);
                    break;
                case 5:
                    //wprintf(L"File renamed (new name): %s\n", file);
                    break;
            }
        },nullptr);
    };
    std::list<std::wstring> drivers;
    for(int i=0;i<26;++i){
        std::wstringstream ss;
        ss << (wchar_t)(L'a'+i)<<":";
        if(std::filesystem::exists(ss.str())){
            drivers.emplace_back(ss.str());
        }
    }
    pool=std::make_shared<boost::asio::thread_pool>(std::thread::hardware_concurrency());
    for(auto id:drivers) boost::asio::post(*pool.get(), std::bind(scan_file, id, &root));
    //boost::asio::post(*pool.get(), std::bind(scan_file, L"D:\2024\\Document"));
    pool->wait();
    // SaveData(data_container,true);
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
    std::wcout<<"scan took "<<duration.count()<<" seconds to execute."<<std::endl;

    pool=std::make_shared<boost::asio::thread_pool>(std::thread::hardware_concurrency());
    for(auto id:drivers) boost::asio::post(*pool.get(), std::bind(watch_file, id, &root));
    pool->wait();
    return 0;
}